﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Net;
using System.Xml.XPath;
using Rappelz.GameServer.Database;

namespace Rappelz.GameServer
{

    public static class Config
    {
        public struct ConfigNet
        {
            public IPAddress ListenIp;
            public IPAddress SentIp;
            public int Port;
            public int ConnLimit;
            public int ListenLimit;
            public bool Encrypted;
            public string Name;
            public string PacketInTxt;
            public string PacketOutText;

            public ConfigNet(XElement root)
            {
                ListenIp = IPAddress.Any;
                SentIp = IPAddress.Any;
                Port = 0;
                ConnLimit = 0;
                ListenLimit = 0;
                Name = "";
                PacketInTxt = "";
                PacketOutText = "";
                Encrypted = true;


                if (root != null)
                {
                    string ip = Config.XmlToString(root.Element("listenip"));
                    if(ip != "0.0.0.0")
                    {
                        IPAddress.TryParse(ip, out ListenIp);
                    }

                    ip = Config.XmlToString(root.Element("sentip"));
                    if (ip != "0.0.0.0")
                    {
                        IPAddress.TryParse(ip, out SentIp);
                    }

                    Port = Config.XmlToInt32(root.Element("port"));
                    ConnLimit = Config.XmlToInt32(root.Element("limit"),200);
                }
            }
        }

        public struct ConfigDb
        {
            public GameDBManager.DatabaseType dbType;
            public string dbConnStr;
            public int dbThreadCount;

            public ConfigDb(XElement root)
            {
                dbType = GameDBManager.DatabaseType.SQLServer;
                dbConnStr = "";
                dbThreadCount = 4;

                if (root != null)
                {
                    this.dbType = (GameDBManager.DatabaseType)Config.XmlToInt32(root.Element("type"));
                    this.dbConnStr = Config.XmlToString(root.Element("connstr"));
                    this.dbThreadCount = Config.XmlToInt32(root.Element("threads"),4);
                }
            }
        }

        static public ConfigDb dbArcadia;
        static public ConfigDb dbTelecaster;
        static public ConfigNet srvGameClients;
        static public ConfigNet connAuthServer;

        static public int nIndex = 1;
        static public String szServerName;
        static public String szScreenshot;
        static public bool bDebug = false;

        public static bool Load(String filename)
        {
            /*try   //if this section throw an exception, the gameserver cannot continue so don't catch
            {*/
                XDocument xd = XDocument.Load(filename);

                if (xd.Root.Name != "options")
                {
                    throw new Exception(filename + " is not a valid gameserver configuration file !");
                }

                XElement xel = xd.Root.XPathSelectElement("./dbarcadia");
                dbArcadia = new ConfigDb(xel);
                xel = xd.Root.XPathSelectElement("./dbtelecaster");
                dbTelecaster = new ConfigDb(xel);
                
                xel = xd.Root.XPathSelectElement("./client");
                srvGameClients = new ConfigNet(xel);
                srvGameClients.Name = "GameClientSever";
                srvGameClients.PacketInTxt = "Client2Game";
                srvGameClients.PacketOutText = "Game2Client";

                xel = xd.Root.XPathSelectElement("./auth");
                connAuthServer = new ConfigNet(xel);
                connAuthServer.Encrypted = false;
                connAuthServer.Name = "LoginClient";
                connAuthServer.PacketInTxt = "Login2Game";
                connAuthServer.PacketOutText = "Game2Login";

                xel = xd.Root.XPathSelectElement("./misc");
                nIndex = XmlToInt32(xel.Element("index"));
                szServerName = XmlToString(xel.Element("name"), "GAME001");
                szScreenshot = XmlToString(xel.Element("screenshot"), "about:blank");
                GameRule.bIsNoCollisionCheck = XmlToBool(xel.Element("bIsNoCollisionCheck"), false);
                GameRule.bRestrictSpecialChar = XmlToBool(xel.Element("bRestrictSpecialChar"), false);
                GameRule.bUseLoginLogoutDebug = XmlToBool(xel.Element("bUseLoginLogoutDebug"), true);
                GameRule.bForceUnregisterAccountOnKickFail = XmlToBool(xel.Element("bForceUnregisterAccountOnKickFail"), true);
                GameRule.bLimitFieldLogout = XmlToBool(xel.Element("bLimitFieldLogout"), false);
                GameRule.bLimitGameTime = XmlToBool(xel.Element("bLimitGameTime"), false);
                GameRule.bDisableCreateCharacter = XmlToBool(xel.Element("bDisableCreateCharacter"), false);
                GameRule.bUseSecurityNoForDeletingCharacter = XmlToBool(xel.Element("bUseSecurityNoForDeletingCharacter"), false);
                GameRule.bUseAutoJail = XmlToBool(xel.Element("bUseAutoJail"), false);
                GameRule.bAutoOpen = XmlToBool(xel.Element("bAutoOpen"), false);
                GameRule.bIsCashUsableServer = XmlToBool(xel.Element("bIsCashUsableServer"), false);
                GameRule.bIsCashUsableServer = XmlToBool(xel.Element("bIsCashUsableServer"), false);
                GameRule.bUsePlayPoint = XmlToBool(xel.Element("bUsePlayPoint"), false);
                GameRule.bSkipLoadingAttribute = XmlToBool(xel.Element("bSkipLoadingAttribute"), false);
                GameRule.bChangeMonsterDropSet = XmlToBool(xel.Element("bChangeMonsterDropSet"), false);
                GameRule.bMonsterWandering = XmlToBool(xel.Element("bMonsterWandering"), true);
                GameRule.bIsPKServer = XmlToBool(xel.Element("bIsPKServer"), false);
                GameRule.bMonsterPathFinding = XmlToBool(xel.Element("bMonsterPathFinding"), true);
                GameRule.bLimitDungeonEnterableLevel = XmlToBool(xel.Element("bLimitDungeonEnterableLevel"), false);
                GameRule.bNoSkillCooltime = XmlToBool(xel.Element("bNoSkillCooltime"), false);
                GameRule.bIgnoreSkillCoolTime = XmlToBool(xel.Element("bIgnoreSkillCoolTime"), false);
                GameRule.bBroadcastEventItemPickup = XmlToBool(xel.Element("bBroadcastEventItemPickup"), true);
                GameRule.bUseSecurityNoForStorage = XmlToBool(xel.Element("bUseSecurityNoForStorage"), false);
                GameRule.bCheckStorageSecurityAlways = XmlToBool(xel.Element("bCheckStorageSecurityAlways"), false);
                GameRule.bRedNameMobsFirstAttack = XmlToBool(xel.Element("bRedNameMobsFirstAttack"), false);

                GameRule.szServerName = szServerName;
                GameRule.szUrlList = XmlToString(xel.Element("szUrlList"), "");

                GameRule.nMaxGameTimeLimitedAge = XmlToInt32(xel.Element("nMaxGameTimeLimitedAge"),18);
                GameRule.nMaxTiredGameTime = XmlToInt32(xel.Element("nMaxTiredGameTime"),0);
                GameRule.nMaxHealthyGameTime = XmlToInt32(xel.Element("nMaxHealthyGameTime"),0);
                GameRule.nCurrentLocalFlag = (uint)XmlToInt32(xel.Element("nCurrentLocalFlag"),4);
                GameRule.nSchedulerThreads = (uint)XmlToInt32(xel.Element("nSchedulerThreads"),4);
                GameRule.nPeriodicalNPCAdjustment = (uint)XmlToInt32(xel.Element("nPeriodicalNPCAdjustment"), 0);
                GameRule.nMaxLevel = XmlToInt32(xel.Element("nMaxLevel"),300);
                GameRule.nMaxStorageItemCount = XmlToInt32(xel.Element("nMaxStorageItemCount"),1000);
                GameRule.nCurrentEventID = XmlToInt32(xel.Element("nCurrentEventID"),0);
                GameRule.nEnhanceFailType = XmlToInt32(xel.Element("nEnhanceFailType"),2);
                GameRule.nItemHold = (uint)XmlToInt32(xel.Element("nItemHold"), 30000);
                GameRule.nClientVersion = (int)XmlToInt32(xel.Element("nClientVersion"), 74);

                GameRule.fPVPDamageRateForPlayer = XmlToSingle(xel.Element("fPVPDamageRateForPlayer"), 0.2f);
                GameRule.fPVPDamageRateForSummon = XmlToSingle(xel.Element("fPVPDamageRateForSummon"), 0.13f);
                GameRule.fAllyPCBangChaosBonusRate = XmlToSingle(xel.Element("fAllyPCBangChaosBonusRate"), 0.2f);
                GameRule.fPremiumPCBangChaosBonusRate = XmlToSingle(xel.Element("fPremiumPCBangChaosBonusRate"), 0.1f);

                GameRule.fPremiumPCBangGoldBonusDropRate = XmlToSingle(xel.Element("fPremiumPCBangGoldBonusDropRate"), 1.0f);
                GameRule.fPremiumPCBangItemBonusDropRate = XmlToSingle(xel.Element("fPremiumPCBangItemBonusDropRate"), 1.0f);
                GameRule.fPremiumPCBangChaosBonusDropRate = XmlToSingle(xel.Element("fPremiumPCBangChaosBonusDropRate"), 1.0f);
                GameRule.fCrimeLimit = XmlToSingle(xel.Element("fCrimeLimit"), 1000.0f);
                GameRule.fSemiCrimeLimit = XmlToSingle(xel.Element("fSemiCrimeLimit"), 500.0f);
                GameRule.fMoralLimit = XmlToSingle(xel.Element("fMoralLimit"), 100.0f);
                GameRule.fSummonStatminaSaveBonusRate = XmlToSingle(xel.Element("fSummonStatminaSaveBonusRate"), 0.5f);
                GameRule.fEXPRate = XmlToSingle(xel.Element("fEXPRate"), 1.0f);
                GameRule.fPartyEXPRate = XmlToSingle(xel.Element("fPartyEXPRate"), 1.0f);
                GameRule.fStaminaBonusRate = XmlToSingle(xel.Element("fStaminaBonusRate"), 1.0f);
                GameRule.fGoldDropRate = XmlToSingle(xel.Element("fGoldDropRate"), 1.0f);
                GameRule.fItemDropRate = XmlToSingle(xel.Element("fItemDropRate"), 1.0f);
                GameRule.fFieldSpawnMultiply = XmlToSingle(xel.Element("fFieldSpawnMultiply"), 0.5f);
                GameRule.fChaosDropRate = XmlToSingle(xel.Element("fChaosDropRate"), 1.0f);

// 
//         public static uint nLogoutTimer = 0;

                bDebug = XmlToBool(xel.Element("debug"));
            /*}
            catch (System.Exception ex)
            {
                //At this time, Globals.Log is null
                Globals.Log.Error("Exception: {0}", ex);
            }*/
            return true;

        }

        public static bool XmlToBool(XElement xml)
        {
            if (xml == null) return false;
            return xml.Value.ToLower() == "true";
        }

        public static bool XmlToBool(XElement xml, bool dv)
        {
            if (xml == null) return dv;
            return xml.Value.ToLower() == "true";
        }

        public static Int32 XmlToInt32(XElement xml)
        {
            if (xml == null) return 0;
            return ToInt32(xml.Value);
        }

        public static float XmlToSingle(XElement xml)
        {
            if (xml == null) return 0.0f;
            return ToInt32(xml.Value);
        }

        public static float XmlToSingle(XElement xml, float dv)
        {
            if (xml == null) return dv;
            return ToSingle(xml.Value, dv);
        }

        public static Int32 XmlToInt32(XElement xml, Int32 dv)
        {
            if (xml == null) return dv;
            return ToInt32(xml.Value,dv);
        }

        public static String XmlToString(XElement xml)
        {
            if (xml == null) return "";
            return xml.Value;
        }
        public static String XmlToString(XElement xml, string szDefault)
        {
            if (xml == null) return szDefault;
            if (!String.IsNullOrEmpty(xml.Value))
                return xml.Value;
            return szDefault;
        }

        public static bool XmlToBool(XAttribute xml)
        {
            if (xml == null) return false;
            return xml.Value.ToLower() == "true";
        }

        public static Int32 XmlToInt32(XAttribute xml)
        {
            if (xml == null) return 0;
            return ToInt32(xml.Value);
        }

        public static String XmlToString(XAttribute xml)
        {
            if (xml == null) return "";
            return xml.Value;
        }

        public static Int32 ToInt32(object Expression)
        {
            bool isNum;
            Int32 retNum;
            isNum = Int32.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            if (isNum) return retNum;
            return 0;
        }
        public static Int32 ToInt32(object Expression, Int32 def)
        {
            bool isNum;
            Int32 retNum;
            isNum = Int32.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            if (isNum) return retNum;
            return def;
        }

        public static float ToSingle(object Expression)
        {
            bool isNum;
            float retNum;
            isNum = Single.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            if (isNum) return retNum;
            return 0.0f;
        }
        public static float ToSingle(object Expression, float def)
        {
            bool isNum;
            float retNum;
            isNum = Single.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            if (isNum) return retNum;
            return def;
        }

    }
}
